--[[--
类名:ScrollSelectView.lua
创建日期: 2015-8-10
创建人: 金剑
功能描述: 滑动选择UI
修改内容：
修改日期:   
修改人:     
修改备注: 
]]

local Vector = require("app.utils.Vector")

local ScrollSelectView = class("ScrollSelectView", function()
	return display.newLayer()
end)

local ScrollDir={
    none = 1,       
    right= 2,
    left = 3,   
    up   = 4,
    down = 5,
}

ScrollSelectView.MoveDir = {
    horizontal = 1,
    vertical = 2,
}

function ScrollSelectView:ctor()
	
    self.m_firstPositionX = 0
    self.m_firstPositionY = 0
	self.m_items = Vector.new()

    self.m_bNeedScroll = false

    self.m_limitLength = 200
    self.m_minMoveLength = -self.m_limitLength
    self.m_maxMoveLength = self.m_limitLength

    --初始化数据
    self.m_selectIndex = 1

    --1像素缩放0.002
    --local precent = (1 - distance*0.002)

    self.m_itemSpace = 100

    self.mbIsScale = false

    self.m_degreesFactor = 3.33 -- 移动一像素转动3.33度

    self.m_movedLength = 0

    self.m_radius = 0 --半径，如果为0表示直线，否则为弧形

    self.m_moveDir = ScrollSelectView.MoveDir.horizontal

    local listener = cc.EventListenerTouchOneByOne:create()
    listener:setSwallowTouches(false)
    listener:registerScriptHandler(handler(self,ScrollSelectView.onTouchBegan),cc.Handler.EVENT_TOUCH_BEGAN)
    listener:registerScriptHandler(handler(self,ScrollSelectView.onTouchEnded),cc.Handler.EVENT_TOUCH_ENDED)
    listener:registerScriptHandler(handler(self,ScrollSelectView.onTouchMoved),cc.Handler.EVENT_TOUCH_MOVED)
    listener:registerScriptHandler(handler(self,ScrollSelectView.onTouchCancelled),cc.Handler.EVENT_TOUCH_CANCELLED)
    local eventDispatcher = self:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)

    self:scheduleUpdate( handler(self, ScrollSelectView.updateFrame))
    
end

function ScrollSelectView:setItemSpace(space)
    if space and type(tonumber(space)) == "number" then
        self.m_itemSpace = tonumber(space)
    end
end

function ScrollSelectView:setNeedScale(isScale)
    if type(isScale) == "boolean" then
        self.mbIsScale = isScale
    end
end

function ScrollSelectView:updateFrame(dt)
    if self.m_bNeedScroll then
        local itemToCenterDistance = (self.m_selectIndex - 1) * self.m_itemSpace + self.m_movedLength
        local offsetValue = self:getItemToCenterOffsetValue(itemToCenterDistance)

        local a = math.abs(offsetValue)*3
        local speed = 350 + a

        local distance = speed*dt
        if math.abs(offsetValue) < distance then
            distance = -offsetValue
            self.m_bNeedScroll = false
            self:selectCallBack()
        else
            if offsetValue > 0 then
                distance = -distance
            end
        end
        
        self:moveLayer(distance)
    end
end

function ScrollSelectView:selectCallBack()
   if self.m_selectCallback then
        local item = self.m_items:get(self.m_selectIndex)
        if item then
            self.m_selectCallback(item.data)    
        end
   end
end

function ScrollSelectView:getSelectItemData()
    local item = self.m_items:get(self.m_selectIndex)
    if item then
        return item.data
    end
    return nil
end

function ScrollSelectView:setCallBack(selectCallback, touchBeganCallBack, touchEndCallBack, itemMoveCallBack)
    self.m_selectCallback = selectCallback
    self.m_touchBeganCallback = touchBeganCallBack
    self.m_touchEndCallback = touchEndCallBack
    self.m_itemMoveCallBack = itemMoveCallBack
end

function ScrollSelectView:setItemModel(model)

    if model == nil then
        return
    end
    
    self._model = model

    local size = model:getContentSize()
    local anchorPoint = model:getAnchorPoint()
    model:setAnchorPoint(cc.p(0.5, 0.5))
    -- self._model_position_y = size.height/2
    self.m_firstPositionX = self.m_firstPositionX 
    self.m_firstPositionY = self.m_firstPositionY
end

function ScrollSelectView:setTouchRect(size)
    self.m_bUseWorldLocation = false
    self.m_touchRect = cc.rect(0, 0, size.width, size.height)
end

function ScrollSelectView:setWorldTouchRect(x, y, width, height)
    self.m_bUseWorldLocation = true
    self.m_worldTouchRect = cc.rect(x, y, width, height)
end

function ScrollSelectView:setMoveDir(dir)
    if dir == ScrollSelectView.MoveDir.vertical then
        self.m_moveDir = ScrollSelectView.MoveDir.vertical
    else
        self.m_moveDir = ScrollSelectView.MoveDir.horizontal
    end
end

function ScrollSelectView:setScrollRadius(radius)
    if radius and type(radius) == "number" then
        self.m_radius = radius
    else
        self.m_radius = 0
    end
end

function ScrollSelectView:setFirstItemPositon(x, y)
    self.m_firstPositionX = x
    self.m_firstPositionY = y
end

function ScrollSelectView:initShowItems()
    self.m_selectIndex = 1
end

function ScrollSelectView:pushBackDefaultItem()
    if self._model == nil then
        return
    end

    local itemcount = self.m_items:size()

    local newItem = self._model:clone()

    self:setItemsParam(newItem, itemcount + 1)

    --关闭子节点触摸，以防止阻挡到layer的触摸滑动
    newItem:setTouchEnabled(true)
    newItem:setSwallowTouches(false)
    newItem:setTag(itemcount + 1)
    local function touchEvent_selectItem(sender, eventType)
        if eventType == ccui.TouchEventType.began then
            -- print("touched----began-------------------------")
        elseif eventType == ccui.TouchEventType.moved then
            -- print("touched-----moved------------------------")
        elseif eventType == ccui.TouchEventType.canceled then
            -- print("touched-----canceled------------------------")
        elseif eventType == ccui.TouchEventType.ended then
            -- print("touched-----ended------------------------")
            
            local tag = sender:getTag()
            self:selectItem(tag)
            self:setScrollLayerAutoMove()

            if self.m_isTouchBegin then
                self.m_isTouchBegin = false
                if self.m_touchEndCallback then
                    self.m_touchEndCallback()
                end
            end
        end
    end
    newItem:addTouchEventListener(touchEvent_selectItem)


    --newItem:setPosition(cc.p(0,0))
    self:addChild(newItem)
    self.m_items:add(newItem)

    local itemcount = self.m_items:size()
    self.m_minMoveLength = -((itemcount - 1) * self.m_itemSpace + self.m_limitLength)
    self.m_maxMoveLength = self.m_limitLength
end

function ScrollSelectView:getItems()
	return self.m_items
end

function ScrollSelectView:moveLayer(distance)
    self.m_movedLength = self.m_movedLength + distance

    if self.m_movedLength < self.m_minMoveLength then
        self.m_movedLength = self.m_minMoveLength
    elseif self.m_movedLength > self.m_maxMoveLength then
        self.m_movedLength = self.m_maxMoveLength
    end

    self:refreshItems()
end

function ScrollSelectView:refreshItems()
    local itemcount = self.m_items:size()
    for i=1,itemcount do
        local item = self.m_items:get(i)

        self:setItemsParam(item, i)
    end
end

function ScrollSelectView:setItemsParam(item, index)
    local itemToCenterDistance = (index - 1) * self.m_itemSpace + self.m_movedLength
    
    local offsetX = 0
    local offsetY = 0
    local degress = itemToCenterDistance/self.m_degreesFactor

    local offsetValue = self:getItemToCenterOffsetValue(itemToCenterDistance)
    if self.m_radius and self.m_radius ~= 0 then
        offsetValue = math.abs(self.m_radius)*math.sin(math.rad(degress))
    end

    if self.m_moveDir == ScrollSelectView.MoveDir.horizontal then
        offsetX = offsetValue
        if self.m_radius == 0 then
            offsetY = 0
        else
            offsetY = math.abs(self.m_radius) - math.sqrt(self.m_radius*self.m_radius - offsetX*offsetX)
            if self.m_radius < 0 then
                offsetY = -offsetY
            end
        end
    else
        offsetY = offsetValue
        if self.m_radius == 0 then
            offsetX = 0
        else
            offsetX = math.abs(self.m_radius) - math.sqrt(self.m_radius*self.m_radius - offsetY*offsetY)
            if self.m_radius < 0 then
                offsetX = -offsetX
            end
        end
    end

    -- if self.m_radius == 0 then
    --     offsetY = 0
    -- else
    --     offsetY = self.m_radius - math.sqrt(self.m_radius*self.m_radius - offsetX*offsetX)
    -- end
    item:setPosition(cc.p(self.m_firstPositionX + offsetX, self.m_firstPositionY + offsetY))

    -- local radius = 600
    -- item:setPosition(cc.p(self.m_firstPositionX + offsetX, self._model_position_y + radius - math.sqrt(radius*radius - offsetX*offsetX)))

    --优化，否则如果有太多item的话，会卡
    if self.m_radius and self.m_radius ~= 0 then
        if degress <= (90) and degress >= - 90 then
            -- print("111------------degress:"..degress)
        else
            item:setPosition(cc.p(-display.width, -display.height))
            return
        end
    else
        if self.m_moveDir == ScrollSelectView.MoveDir.horizontal then
            if math.abs(offsetX) > display.width then
                return
            end
        else
            if math.abs(offsetY) > display.height then
                return
            end
        end
    end

    --1像素缩放0.002
    local precent = (1 - math.abs(itemToCenterDistance)*0.0015)
    if precent < 0.5 then
        precent = 0.5
    end

    if self.mbIsScale then
        item:setScale(precent)
    end

    -- display.setWidgetColor(item, cc.c3b(255 - 180*(1-precent), 255 - 180*(1-precent), 255 - 180*(1-precent)))

    -- local opacity = 255 - 200*(1-precent)
    -- if opacity < 0 then
    --     opacity = 0
    -- end
    -- display.setWidgetOpacity(item, opacity)

    if self.m_itemMoveCallBack then
        local opacity = (100.0 - math.abs(degress))*255.0/100.0
        self.m_itemMoveCallBack(item, opacity)
        -- local uiIconBg = item:getChildByName("Icon_bg")
        -- display.setWidgetOpacity(uiIconBg, opacity)
    end
end

function ScrollSelectView:getItemToCenterOffsetValue(itemToCenterDistance)
    local offsetValue = itemToCenterDistance
    if self.m_radius and self.m_radius ~= 0 then
        --弧形运动
        -- local degress = itemToCenterDistance/self.m_degreesFactor
        -- print("-----------degress:"..degress)
        -- offsetValue = math.abs(self.m_radius)*math.sin(math.rad(degress))
    else
        if math.abs(itemToCenterDistance) > self.m_itemSpace then 

            if itemToCenterDistance > 0 then
                local distance = math.pow(math.abs(itemToCenterDistance - self.m_itemSpace), 0.8)
                offsetValue = self.m_itemSpace + distance*2
            else
                local distance = math.pow(math.abs(itemToCenterDistance + self.m_itemSpace), 0.8)
                offsetValue = -self.m_itemSpace - distance*2
            end

            -- if itemToCenterDistance > 0 then
            --     local distance = (math.abs(itemToCenterDistance - self.m_itemSpace))
            --     offsetValue = self.m_itemSpace + distance*0.6
            -- else
            --     local distance = (math.abs(itemToCenterDistance + self.m_itemSpace))
            --     offsetValue = -self.m_itemSpace - distance*0.6
            -- end
        end
    end
    return offsetValue
end

function ScrollSelectView:onTouchBegan(touch, event)
    -- print("ScrollSelectView onTouchBegan---------------------------")
    local isTouchRect = false
    if self.m_bUseWorldLocation then
        isTouchRect = cc.rectContainsPoint(self.m_worldTouchRect, touch:getLocation())
    else
        local locationInNode = self:convertToNodeSpace(touch:getLocation())
        isTouchRect = cc.rectContainsPoint(self.m_touchRect, locationInNode)
    end
    
    if isTouchRect then
        self.m_isTouchBegin = true
        if self.m_touchBeganCallback then
            self.m_touchBeganCallback()
        end
        return true
    end

    
    return false
end

function ScrollSelectView:onTouchEnded(touch, event)
    -- print("ScrollSelectView onTouchEnded---------------------------")
    if self.m_isTouchBegin then
        self.m_isTouchBegin = false
        if self.m_touchEndCallback then
            self.m_touchEndCallback()
        end
        self:checkLayerNeedScroll()
    end
end


function ScrollSelectView:onTouchMoved(touch, event)
    -- print("ScrollSelectView onTouchMoved---------------------------")
    local delta = touch:getDelta()
    local distance = 0
    if self.m_moveDir == ScrollSelectView.MoveDir.horizontal then
        distance = delta.x
        self:moveLayer(distance)
        if distance > 0 then
            self.m_scrolldir = ScrollDir.right
        else
            self.m_scrolldir = ScrollDir.left
        end 
    else
        distance = delta.y
        self:moveLayer(distance)
        if distance > 0 then
            self.m_scrolldir = ScrollDir.up
        else
            self.m_scrolldir = ScrollDir.down
        end
    end    
end

function ScrollSelectView:onTouchCancelled(touch, event)
    -- print("ScrollSelectView onTouchCancelled---------------------------")
    self.m_isTouchBegin = false
    if self.m_touchEndCallback then
        self.m_touchEndCallback()
    end
    self:checkLayerNeedScroll()
end

function ScrollSelectView:checkLayerNeedScroll()
    local itemcount = self.m_items:size()
    local index = 1
    local minOffsetValue = self.m_itemSpace
    self.m_bNeedScroll = true
    for i=1,itemcount do
        local item = self.m_items:get(i)
        local itemToCenterDistance = (i - 1) * self.m_itemSpace + self.m_movedLength
        local offsetValue = self:getItemToCenterOffsetValue(itemToCenterDistance)

        --初始minOffsetValue
        if i == 1 then
            minOffsetValue = offsetValue
        end

        --如果是0
        if offsetX == 0 then
            -- self:selectItem(i)
            self.m_bNeedScroll = false
            minOffsetValue = offsetValue
            index = i
            break
        else
            if math.abs(minOffsetValue) > math.abs(offsetValue) then
                minOffsetValue = offsetValue
                index = i
            end
        end
    end

    if self.m_scrolldir == ScrollDir.right then
        if minOffsetValue <= 0 then
            self:selectItem(index)
        else
            if index - 1 >= 1 then
                self:selectItem(index - 1)
            else
                self:selectItem(index)
            end
        end
    elseif self.m_scrolldir == ScrollDir.left then
        if minOffsetValue >= 0 then
            self:selectItem(index)
        else
            if index + 1 <= itemcount then
                self:selectItem(index + 1)
            else
                self:selectItem(index)
            end
        end
    elseif self.m_scrolldir == ScrollDir.up then
        if minOffsetValue <= 0 then
            self:selectItem(index)
        else
            if index - 1 >= 1 then
                self:selectItem(index - 1)
            else
                self:selectItem(index)
            end
        end
    elseif self.m_scrolldir == ScrollDir.down then
        if minOffsetValue >= 0 then
            self:selectItem(index)
        else
            if index + 1 <= itemcount then
                self:selectItem(index + 1)
            else
                self:selectItem(index)
            end
        end
    end

    if self.m_bNeedScroll == false then
        self:selectCallBack()
    end
end

function ScrollSelectView:selectItem(index)
    self.m_selectIndex = index
end

function ScrollSelectView:setScrollLayerAutoMove()
    self.m_bNeedScroll = true
end

function ScrollSelectView:ScrollToSelectItem()
    self.m_movedLength = -(self.m_selectIndex - 1) * self.m_itemSpace

    self:refreshItems()
end

return ScrollSelectView
